package im.oen.boot.common.utils;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import im.oen.boot.common.constant.OenCode;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * 序列化工具
 *
 * @author Kevin.Xu
 */
public class SerializeUtil {
    private static final ThreadLocal<LinkedBuffer> BUFFERS = new ThreadLocal();
    private static final Map<Class<?>, Schema<?>> schemaCache = new HashMap<>();

    private static <T> Schema<T> getSchema(Class<T> clazz) {
        Schema<?> schema = schemaCache.get(clazz);
        if (schema == null) {
            schema = RuntimeSchema.createFrom(clazz);
            schemaCache.put(clazz, schema);
        }
        return (Schema<T>) schema;
    }

    private static LinkedBuffer getBuffer() {
        LinkedBuffer buffer = BUFFERS.get();
        if (buffer == null) {
            buffer = LinkedBuffer.allocate(4096);
            BUFFERS.set(buffer);
        }
        return buffer;
    }

    public static <T extends Serializable> byte[] obj2Bit(T obj) {
        if (Checker.isEmpty(obj)) {
            return null;
        }

        Schema<T> schema = getSchema((Class<T>) obj.getClass());
        LinkedBuffer buffer = getBuffer();

        try {
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } catch (Exception e) {
            throw OenCode.SERIALIZE_ERROR.exception(e);
        } finally {
            buffer.clear();
        }
    }

    public static <T extends Serializable> T bit2Obj(byte[] bytes, Class<T> clazz) {
        if (Checker.isEmpty(bytes)) {
            return null;
        }

        try {
            Schema<T> schema = getSchema(clazz);
            T message = schema.newMessage();
            ProtostuffIOUtil.mergeFrom(bytes, message, schema);
            return message;
        } catch (Exception e) {
            throw OenCode.SERIALIZE_ERROR.exception(e);
        }
    }
}
